#include "miniutil/buffer_alloc.h"
#include "miniutil/socketcmn.h"
#include "miniutil/lenmsgreader.h"

namespace miniutil { namespace multinet {

/*
    090811 NOT TEST!
*/

LenMsgSource_Soc::LenMsgSource_Soc(SOCKET soc)
    :msoc(soc)
{
}

int LenMsgSource_Soc::Recv(char* pbuf, int len)
{
    return ::recv(msoc, pbuf, len, 0);
}

LenMsgSource_Sms::LenMsgSource_Sms(miniutil::multinet::SocketMulplexService* pse, SOCKET soc)
    :mpss(pse), msoc(soc)
{
}

int LenMsgSource_Sms::Recv(char* pbuf, int len)
{
    return mpss->recv(msoc, pbuf, len);
}


LenMsgSource_Fifo::LenMsgSource_Fifo(miniutil::data::fifobuf *pfifo)
    :mpfifo(pfifo)
{
}

int LenMsgSource_Fifo::Recv(char* pbuf, int len)
{
    return mpfifo->read(pbuf, len);
}




//the format of message must have 4 byte length indicate following message lenth
//-------------------------------------------------------------------------------
LenMsgReader::LenMsgReader(int offset, int size)
{
    mlenoffset = offset;
    mlensize = size;
    assert(mlensize <= 4);
    assert(mlensize > 0);

    assert(mlenoffset+mlensize < sizeof(tmpbuf));

    msglen = -1;
    msghaveread = 0;
    pbuf = NULL;
    memset(tmpbuf, 0x00, sizeof(tmpbuf));
}

LenMsgReader::~LenMsgReader()
{
	Clear();
}

int LenMsgReader::GetMsgBufLen()
{
	return msglen + mlenoffset + mlensize;
}

char* LenMsgReader::RefMsgBuf()
{
	return pbuf;
}	

int LenMsgReader::Read(SOCKET soc)
{
    LenMsgSource_Soc source(soc);
    return Read(&source);
}
//the pse(soc) must be readable!
int LenMsgReader::Read(miniutil::multinet::SocketMulplexService* pse, SOCKET soc)
{
    LenMsgSource_Sms source(pse, soc);
    return Read(&source);
}

int LenMsgReader::Read(miniutil::data::fifobuf* pfifo)
{
    LenMsgSource_Fifo source(pfifo);
    return Read(&source);
}

int LenMsgReader::Read(LenMsgSource* psrc)
{
    int ret = 0, ret2;
    int lentoread = 0;
    int atleastread = mlenoffset + mlensize;
    if(msglen == -1)
    {
        lentoread = atleastread-msghaveread;
        ret = psrc->Recv(tmpbuf+msghaveread, lentoread);
        if(ret == -1 || ret == 0)
        {
            miniutil::socketcmn::check_cursoc_error();
            return -1;
        }
        msghaveread += ret;
        if(msghaveread == atleastread)
        {            
            msglen = 0;
            for(int i=0; i< mlensize; i++)
            {
                msglen = msglen << 8;
                //MUST CARE OF PLUS one CHAR int value
                msglen += ((*(tmpbuf+mlenoffset+i))&0xFF);
            }
            
            //pbuf = new char[msglen+atleastread];
            pbuf = miniutil::data::pool_buffer_alloc::getdefaultinstance()->retrieve_mem(msglen+atleastread);
            memcpy(pbuf, tmpbuf, atleastread);
            
            msghaveread = 0;
        }
    }
    
    if(msglen != -1)
    {
        lentoread = msglen - msghaveread;
        ret2 = psrc->Recv(pbuf+atleastread+msghaveread, lentoread);
        if(ret2 == -1)
        {
            miniutil::socketcmn::check_cursoc_error();
            return -1;
        }
        else if(ret2 ==0 && ret == 0)
            return -1;
        msghaveread += ret2;
    }
    
    if(msglen != -1 && msglen == msghaveread)
        return 1;
    
    return 0;
}

int LenMsgReader::Clear()
{
    msglen = -1;
    msghaveread = 0;
    if(pbuf)
		miniutil::data::pool_buffer_alloc::getdefaultinstance()->release_mem(pbuf);
        //delete []pbuf;
    pbuf = NULL;
    memset(tmpbuf, 0x00, sizeof(tmpbuf));
    return 0;
}
	
} }

	